/**
 * This file is part of Lineage II Client Data Parser.
 * 
 * Lineage II Client Data Parser is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * Lineage II Client Data Parser is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with Lineage II Client Data Parser.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.l2emuproject.parser;

import java.io.IOException;
import java.io.Writer;
import java.nio.BufferUnderflowException;
import java.util.ArrayList;
import java.util.List;

import net.l2emuproject.Launcher;
import net.l2emuproject.entity.SystemMessage;
import net.l2emuproject.io.FileManager;
import net.l2emuproject.io.SafelyPackedFile;
import net.l2emuproject.parser.base.DefaultParser;
import net.l2emuproject.redist.UnsupportedException;

import javolution.text.TextBuilder;

/**
 * @author Savormix
 *
 */
public final class SystemMessageParser extends DefaultParser
{
	private static final String[]		NEEDED_FILES	=
														{ Launcher.FILES[30] };
	private static final String[]		JAVADOC			=
														{ "\t/**", "\t * ", "\t */" };

	private final List<SystemMessage>	list;

	/**
	 * Creates a parser that parses system messages. Needed Files:
	 * <LI>systemmsg-e</LI>
	 * @param spf File array
	 * @throws IllegalArgumentException Wrong file(s) 
	 */
	public SystemMessageParser(SafelyPackedFile... spf) throws IllegalArgumentException
	{
		super(spf);
		list = new ArrayList<SystemMessage>(3000);
	}

	/** Creates a parser that validates files */
	public SystemMessageParser()
	{
		super();
		list = null;
	}

	private final boolean parseMessages(int entryCnt, SafelyPackedFile spf)
	{
		if (!isValidator())
			log.info("Reading " + entryCnt + " entries from " + spf.getFileName());
		for (int i = 0; i < entryCnt; i++)
		{
			if (isValidator())
				return (spf.readInt() == 0 && spf.readInt() == 1);
			try
			{
				int id = spf.readInt();
				log.debug("Reading message " + id);
				list.add(new SystemMessage(id, spf.readInt(), spf.readString(), spf.readInt(), spf.readByte(), spf.readByte(), spf.readByte(), spf.readByte(),
						spf.readString(), spf.readString(), spf.readInt(), spf.readInt(), spf.readInt(), spf.readInt(), spf.readInt(), spf.readString(), spf
								.readString()));
			}
			catch (BufferUnderflowException e)
			{
				log.warn("EOF reached when trying to read element " + i + "/" + entryCnt);
				break;
			}
		}
		log.info("Finished reading " + spf.getFileName());
		return false;
	}

	/* (non-Javadoc)
	 * @see com.l2cdp.parser.base.IParser#getNeededFiles()
	 */
	@Override
	public String[] getNeededFiles()
	{
		return NEEDED_FILES;
	}

	/* (non-Javadoc)
	 * @see com.l2cdp.parser.base.IParser#getParseType()
	 */
	@Override
	public String getParseType()
	{
		return "stored system message";
	}

	/* (non-Javadoc)
	 * @see com.l2cdp.parser.base.IParser#readClientData()
	 */
	@Override
	public void readClientData() throws IllegalAccessException
	{
		if (isValidator())
			throw new IllegalAccessException(toString());
		parseMessages(entries[0], spf[0]);
	}

	/* (non-Javadoc)
	 * @see com.l2cdp.parser.base.IParser#selfAdvancedAnalysis()
	 */
	@Override
	public void selfAdvancedAnalysis() throws IllegalAccessException
	{
		if (isValidator())
			throw new IllegalAccessException(toString());
		for (SystemMessage sm : list)
		{
			if (ANALYZE_DETERMINISTIC)
				sm.deterministicAnalysis();
			if (ANALYZE_EXPERIMENTAL)
				sm.experimentalAnalysis();
		}
	}

	/* (non-Javadoc)
	 * @see com.l2cdp.parser.base.IParser#validate(com.l2cdp.io.SafelyPackedFile)
	 */
	@Override
	public boolean validate(SafelyPackedFile spf)
	{
		try
		{
			return parseMessages(spf.readInt(), spf);
		}
		catch (Exception e)
		{
			return false;
		}
	}

	/* (non-Javadoc)
	 * @see com.l2cdp.parser.base.IParser#writeServerData(int)
	 */
	@Override
	public void writeServerData(int chronicle) throws IllegalAccessException
	{
		if (isValidator())
			throw new IllegalAccessException(toString());
		synchronized (finLock)
		{
			addThread();
		}
		new Thread(new AsyncWriterSMSrv(chronicle), AsyncWriterSMSrv.class.getName()).start();
	}

	/* (non-Javadoc)
	 * @see com.l2cdp.parser.base.IParser#writeSimpleData(int)
	 */
	@Override
	public void writeSimpleData(int chronicle) throws IllegalAccessException
	{
		if (isValidator())
			throw new IllegalAccessException(toString());
		//synchronized (finLock) {
		//	addThread();
		//}
		//new Thread(new AsyncWriterSMSim(chronicle), AsyncWriterSMSim.class.getName()).start();
	}

	protected class AsyncWriterSMSrv implements Runnable
	{
		private static final String	ID	= "ID: ";
		private static final String	MSG	= "Console Message: ";
		private static final String	SUB	= "Screen Message: ";
		private static final String	BR	= "<BR>";

		private final int			cID;

		protected AsyncWriterSMSrv(int cID)
		{
			this.cID = cID;
		}

		/* (non-Javadoc)
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run()
		{
			TextBuilder sb = TextBuilder.newInstance();
			try
			{
				Writer w = FileManager.getWriter(cID, "SystemMessageId.java", false);
				//addGenInfo(cID, sb, COMMENT_JAVA);
				sb.append("public enum SystemMessageId");
				sb.append(LINE_BREAK);
				sb.append('{');
				sb.append(LINE_BREAK);
				for (SystemMessage sm : list)
				{
					sb.append(JAVADOC[0]);
					sb.append(LINE_BREAK);
					sb.append(JAVADOC[1]);
					sb.append(ID);
					sb.append(sm.getId());
					sb.append(BR);
					sb.append(LINE_BREAK);
					sb.append(JAVADOC[1]);
					sb.append(MSG);
					// TODO: perhaps split to pieces?
					sb.append(sm.getMessage());
					if (!sm.getScreenMessage().isEmpty())
					{
						sb.append(BR);
						sb.append(LINE_BREAK);
						sb.append(JAVADOC[1]);
						sb.append(SUB);
						sb.append(sm.getScreenMessage());
					}
					sb.append(LINE_BREAK);
					sb.append(JAVADOC[2]);
					sb.append(LINE_BREAK);
					sb.append('\t');
					sb.append(sm);
					sb.append('(');
					sb.append(sm.getId());
					sb.append(')');
					sb.append(',');
					sb.append(LINE_BREAK);
					sb.append(LINE_BREAK);
				}
				sb.append('}');
				sb.append(LINE_BREAK);
				//addGenInfo(-1, sb, COMMENT_JAVA);
				//sb.delete(sb.length() - LINE_BREAK.length(), sb.length());
				w.write(sb.toString());
				w.close();
			}
			catch (UnsupportedException e)
			{
				log.fatal("Unsupported chronicle, will not write data!", e);
			}
			catch (IOException e)
			{
				log.error("Cannot write SystemMessageId.java!", e);
			}
			finally
			{
				TextBuilder.recycle(sb);
				synchronized (finLock)
				{
					remThread();
				}
			}
		}
	}
}
